"""
彩票数据统计工具
功能包含：
1. 数字出现位置追踪统计
2. 间隔次数统计分析
"""

import json
from collections import defaultdict
from typing import Set, List, Tuple,Dict
import logging
import os
import sys
from logging.handlers import TimedRotatingFileHandler
import requests
import time
from datetime import datetime, timedelta,time as dtime
import configparser
from functools import wraps
from DeviceManagerClient import DeviceManagerClient

def retry_on_failure(max_retries=10, delay=5):
    """装饰器：在失败时重试指定次数"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            retries = 0
            while retries < max_retries:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    retries += 1
                    if retries == max_retries:
                        raise  # 如果达到最大重试次数，重新抛出异常
                    logger.info(f"尝试 {retries}/{max_retries} 失败: {e}，{delay}秒后重试...")
                    time.sleep(delay)
            return None
        return wrapper
    return decorator

def setup_logging(
        name: str = "app",
        log_dir: str = "logs",
        level: str = "INFO",
        when: str = "D",
        backup_count: int = 7,
        fmt: str = "%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
) -> logging.Logger:
    """
    初始化日志配置

    参数：
        name (str): 日志名称/应用名称，默认 'app'
        log_dir (str): 日志存储目录，默认 'logs'
        level (str): 日志级别（DEBUG/INFO/WARNING/ERROR/CRITICAL），默认 'INFO'
        when (str): 日志轮换间隔单位，默认 'D'（天），可选值：
                    'S' 秒, 'M' 分, 'H' 小时, 'D' 天, 'W0'-'W6' 周
        backup_count (int): 保留的旧日志文件数量，默认7
        fmt (str): 日志格式，默认包含时间、级别、模块、行号和消息

    返回：
        logging.Logger: 配置好的Logger对象

    示例：
        >>> logger = setup_logging()
        >>> logger.info("系统启动")
    """
    try:
        # 创建日志目录
        os.makedirs(log_dir, exist_ok=True)

        # 初始化日志对象
        logger = logging.getLogger(name)
        logger.setLevel(level)

        # 清除已有处理器避免重复
        if logger.handlers:
            for handler in logger.handlers[:]:
                logger.removeHandler(handler)

        # 设置日志格式
        formatter = logging.Formatter(fmt=fmt, datefmt="%Y-%m-%d %H:%M:%S")

        # 文件处理器（按时间轮换）
        file_handler = TimedRotatingFileHandler(
            filename=os.path.join(log_dir, f"{name}.log"),
            when=when,
            backupCount=backup_count,
            encoding="utf-8"
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)

        # 控制台处理器
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)

        return logger

    except PermissionError as e:
        sys.stderr.write(f"日志文件写入权限不足: {str(e)}\n")
        raise
    except Exception as e:
        sys.stderr.write(f"日志初始化失败: {str(e)}\n")
        raise


def to_number(value):
    try:
        return int(value)
    except ValueError:
        try:
            return float(value)
        except ValueError:
            return None  # 或者 raise 异常，或者返回默认值


# 号码对应的索引位置
def getOrder_Info_number (position,number):
    data = {
        1: ["160001", "160002", "160003", "160004", "160005", "160006", "160007", "160008", "160009", "160010"],
        2: ["160011", "160012", "160013", "160014", "160015", "160016", "160017", "160018", "160019", "160020"],
        3: ["160021", "160022", "160023", "160024", "160025", "160026", "160027", "160028", "160029", "160030"],
        4: ["160031", "160032", "160033", "160034", "160035", "160036", "160037", "160038", "160039", "160040"],
        5: ["160041", "160042", "160043", "160044", "160045", "160046", "160047", "160048", "160049", "160050"],
        6: ["160051", "160052", "160053", "160054", "160055", "160056", "160057", "160058", "160059", "160060"],
        7: ["160061", "160062", "160063", "160064", "160065", "160066", "160067", "160068", "160069", "160070"],
        8: ["160071", "160072", "160073", "160074", "160075", "160076", "160077", "160078", "160079", "160080"],
        9: ["160081", "160082", "160083", "160084", "160085", "160086", "160087", "160088", "160089", "160090"],
        10: ["160091", "160092", "160093", "160094", "160095", "160096", "160097", "160098", "160099", "160100"]
    }

    # 获取键为2的列表，并访问第三个元素（索引从0开始）
    target_value = data[position][number-1]
    return target_value


#获取请求头
def get_headers(cookie_value):
    return  {
    "Accept": "application/json, text/plain, */*",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Connection": "keep-alive",
    "Cookie": cookie_value,
    "Host": ip,
    "Referer": f"{host}/member/history",
    "sec-ch-ua": '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}

# 确认订单
@retry_on_failure(max_retries=3, delay=3)
def send_order_post_request(cookie_value, xdnum):
    # 构造请求URL
    url = f"{host}/api/mem/lottery/set_order"

    # 构造请求头
    headers = get_headers(cookie_value)

    # 构造请求体
    data = {
        "type": 1,
        "xdnum": xdnum
    }
    logger_order.info("确认订单数据阶段---->")
    # 打印最终替换完的请求参数
    logger_order.info("\nFinal Request Body:")
    logger_order.info(json.dumps(data, indent=4))
    # 当前下注号码
    global betting_number, betting_position, betting_cnt
    # 发送POST请求
    response = requests.post(url, headers=headers, json=data)

    # 检查响应状态码
    if response.status_code == 200:
        logger_order.info("\n请求成功！")
        logger_order.info(f"服务器返回的内容: {response.text}")
        logger.info(f"服务器返回的内容: {response.text}")
    elif response.status_code == 400:
        time.sleep(8)
        logger.info(f"服务器返回的内容: {response.text}")
        requests.post(url, headers=headers, json=data)
    else:
        logger_order.info(f"\n请求失败，状态码: {response.status_code}")
        logger_order.info(f"服务器返回的内容: {response.text}")
        betting_number = None
        betting_position = None
        # 当前下注次数,默认为0
        betting_cnt = betting_cnt - 1

# 发送订单详情
@retry_on_failure(max_retries=3, delay=3)
def send_order_info_post_request(cookie_value, order_str):
    # 构造请求URL
    url=f'{host}/api/mem/lottery/order_info'
    # 构造请求头
    headers = get_headers(cookie_value)

    # 构造请求体
    #order_str = f"{num1},9.705,2|{num2},9.705,2|{num3},9.705,2"
    #order_str = f"{num1},9.705,2"
    data = {
        "order_str": order_str
    }
    logger_order.info("生成订单数据阶段---->")
    logger.info("生成订单数据阶段---->")
    # 打印最终替换完的请求参数
    logger_order.info("\nFinal Request Body:")
    logger_order.info(json.dumps(data, indent=4))
    global betting_number,betting_cnt,betting_position,betting_issue_no,current_issue_no
    control_setting = load_control_settings()

    auto_order = control_setting['auto_order']
    if str(int(current_issue_no) + 1) == betting_issue_no:
        logger.error("已经有下注了，不进行二次下注")
        return
    else:
        betting_issue_no = str(int(current_issue_no) + 1)
    logger_order.error(f"当前下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
    logger.error(f"当前下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
    if auto_order == '1':
        # 发送POST请求
        response = requests.post(url, headers=headers, json=data)
        # 检查响应状态码
        if response.status_code == 200:
            logger_order.info("\n请求成功！")
            logger_order.info(f"服务器返回的内容: {response.text}")
            logger_order.info("生成订单完成---->")
            logger.info("生成订单完成---->")
            # 获取到xd_num
            xd_num = response.json()[-1]['XDnum']
            logger.info(f"获取到的{xd_num}--->开始确定订单")

            send_order_post_request(cookie_value, xd_num)

            logger_order.info(f"--->确定订单结束")
            logger.info(f"--->确定订单结束")
        elif response.status_code == 400:
            time.sleep(8)
            logger.info(f"服务器返回的内容: {response.text}")
            response = requests.post(url, headers=headers, json=data)
            xd_num = response.json()[-1]['XDnum']
            send_order_post_request(cookie_value, xd_num)
            logger_order.info(f"--->确定订单结束")
        else:
            logger_order.info(f"\n请求失败，状态码: {response.status_code}")
            logger_order.info(f"服务器返回的内容: {response.text}")
            logger.info(f"\n请求失败，状态码: {response.status_code}")
            logger.info(f"服务器返回的内容: {response.text}")
            betting_number = None
            betting_position = None
            betting_cnt = betting_cnt - 1
    else:
        logger_order.info(f"当前状态值为：{auto_order}，自动下单按钮没有点击，不进行自动下单---->")
        logger.info(f"当前状态值为：{auto_order}，自动下单按钮没有点击，不进行自动下单---->")
# 爬取数据 如果异常失败了，那么重试3次
@retry_on_failure(max_retries=5, delay=5)
def fetch_and_save_data(cookie_value, count_per_page,page, lottery_id):

    # 创建保存数据的目录
    current_date = datetime.now().strftime('%Y%m%d')
    save_dir = f"spider_data_{current_date}"
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    # 循环请求每一页的数据
    url = f'{host}/api/mem/lottery/history/16?count={count_per_page}&page={page}&lottery_id={lottery_id}'
    headers = get_headers(cookie_value)
    response = requests.get(url, headers=headers)
    # logger.info(f"{url} 请求头->{headers}")

    # 检查响应状态码
    if response.status_code == 200:
        data = response.json()
        # 生成文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f"{save_dir}/{timestamp}_lottery_id_{lottery_id}.json"
        # 保存数据到文件
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=4)
        logger.info(f"Saved data to {filename}")
        return filename
    else:
        logger.error(f"Request failed with status code: {response.status_code}")
        logger.error(f"Response: {response.text}")
        raise Exception(f"Request failed with status code: {response.status_code}")

def read_and_sort_data(file_path: str) -> list:
    """
    读取并预处理彩票数据

    参数：
        file_path: JSON文件路径

    返回：
        按时间排序后的数据列表

    异常：
        FileNotFoundError: 文件不存在时抛出
        ValueError: JSON解析失败时抛出
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
    except FileNotFoundError:
        raise FileNotFoundError(f"数据文件 {file_path} 未找到")
    except json.JSONDecodeError:
        raise ValueError("JSON文件解析失败，请检查格式")

    return sorted(data['items'], key=lambda x: x['open_time'])



def parse_betting_num(betting_str: str) -> Dict[str, str]:
    """解析押注号码映射配置"""
    betting_map = {}
    pairs = betting_str.split(',')
    for pair in pairs:
        key, value = pair.split(':')
                # 如果 key 是数字且小于 10，补 0
        if key.isdigit() and int(key) < 10:
            key = f"{int(key):02d}"  # 补 0，如 1 → "01"
        
        # 如果 value 是数字且小于 10，补 0
        if value.isdigit() and int(value) < 10:
            value = f"{int(value):02d}"  # 补 0，如 2 → "02"
        betting_map[key] = value
    return betting_map


def wait_radical_analysis( file_path: str = 'data/data.json',
                     cookie_value:str = '',
                     ) -> List[int]:
    logger.info(f"<------------------当前是追击模式----------------->")
    # 获取数据
    sorted_items = read_and_sort_data(file_path)
    # 定义最新一期的期号
    global current_issue_no, current_open_code, current_date, next_spider_date, all_cnt, num_and_money,first_in,is_hot,hot_num
    global current_win_num,start_count,is_run_radical,radical_app,current_win_cnt,wheel,init_total_money
    current_open_code = sorted_items[-1]["open_code"]
    current_issue_no = sorted_items[-1]["issue_no"]
    # 定义最新一期的开奖时间，便于下次爬取数据的时间
    current_date = sorted_items[-1]["open_time"]
    # 下次爬取数据的时间
    original_date = datetime.strptime(current_date, "%Y-%m-%d %H:%M:%S")
    # 添加 1分25秒
    delta = timedelta(minutes=1, seconds=25)
    next_spider_date = original_date + delta
    logger.info(f"下次获取数据的时间：{next_spider_date}")
    # 判断有押注的话，是否有中奖。如果有中奖的话追加一期
    global betting_cnt, betting_issue_no, total_money, init_money, betting_money, betting_position, betting_number, win_cnt, win_money, all_money, radical_num, is_run_radical, radical_prefit, current_betting_all_money, last_win,models
    # 押注的期号
    global  trigger_count,choose_number,win_total_count,not_win_cnt,total_num,desc
    # 定义是否压中
    # 定义激进的押注方式
    logger.info(
        f"betting_cnt={betting_cnt}，betting_number={betting_number}，betting_position={betting_position}，current_issue_no={current_issue_no}，betting_issue_no={betting_issue_no}")
    # 保存结果
    if (betting_cnt != 0) and (betting_number is not None) and (betting_position is not None) and (
            current_issue_no == betting_issue_no):
        # 比对是否有中奖
        codes = sorted_items[-1]["open_code"].split(',')
        total_count = sum(1 for a, b in zip(codes, betting_number) if a == b)
        if total_count > 0:
            current_win_cnt = current_win_cnt + total_count
            if is_run_radical and  last_win == False:
                logger.error(f"下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
                # 重新计算金额  中奖金额 - 成本
                total_money = total_money + ((betting_money * 9.705) * total_count)
                logger_order.info(f"中奖金额：{((betting_money * 9.705) * total_count)}，剩余可用余额={total_money}")
                logger.info(f"中奖金额：{((betting_money * 9.705) * total_count)}，剩余可用余额={total_money}")
                win_money = win_money + (((betting_money * 9.705)*total_count) - (len(betting_number) * betting_money))
                win_cnt = win_cnt + 1
                win_total_count = win_total_count + total_count
                logger.info(f"<----------------------押注的号码中奖了,中奖了{total_count}次------------------------->")
            else:
                if  last_win:
                     logger.info(f"<----------------------押注的号码中奖了,中奖了{total_count}次。当前是止盈状态，没有下单------------------------->")
                else:     
                    logger.info(f"<----------------------押注的号码中奖了,中奖了{total_count}次。当前不符合等待逻辑，没有下单------------------------->")
        else:
            not_win_cnt = not_win_cnt + 1
            if is_run_radical:
                open_code = sorted_items[-1]["open_code"]
                logger_order.info(f"押注的号码没中奖")
                logger.info(f"<-----------------押注的号码没中奖------------------------>")
                logger.error(
                    f"开奖号码：{open_code} ，押注的号码没中奖！下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
            else:
                logger.info(f"<-----------------押注的号码没中奖,当前不符合等待逻辑，没有下单------------------------>")
    # 计算是否开始下注.计算逻辑：(总的次数/2)-current_win_cnt >= start_count 表示已经等够对应的次数。可以进行下注
    if direct == '>':
        if (total_num -current_win_cnt) >= start_count and  is_run_radical == False:
            is_run_radical = True
            wheel = wheel + 1
            logger.info(f"<----------------符合下单逻辑，开启下单。当前第{wheel}轮------------------------>")
    else:

        if right_now == '1':
            first_in = True

        if (total_num -current_win_cnt) > start_count and first_in == False:
            first_in = True
            logger.info(f"<-----------------第一次满足条件大于指定次数{start_count}----------------------->")
        else:
            if (total_num-current_win_cnt) <= start_count  and first_in == True:
                is_run_radical = True
                wheel = wheel + 1
                logger.info(f"<----------------符合下单逻辑，开启下单。当前第{wheel}轮,当前方向 {direct}------------------------>")
            else:
                is_run_radical = False
                logger.info(f"<----------------不符合下单逻辑，当前第{wheel}轮,当前方向 {direct}------------------------>")
    total_num = total_num + 1
    betting_cnt = 0
    if  last_win:
        logger.info(f"<----------------------押注的号码中奖了,中奖了{total_count}次。当前是止盈状态，没有下单------------------------->")

    # 根据位置获取到目标号码
    open_code = sorted_items[-1]["open_code"].split(',')
    pos_idx = int(trigger_count) - 1
    current_num = open_code[pos_idx]

    betting_map = parse_betting_num(choose_number)
    result = [betting_map.get(open_code[0]), betting_map.get(open_code[1]), betting_map.get(open_code[2]), betting_map.get(open_code[3]), betting_map.get(open_code[4]), betting_map.get(open_code[5]), betting_map.get(open_code[6]), betting_map.get(open_code[7]), betting_map.get(open_code[8]), betting_map.get(open_code[9])]
    desc = f"总的期数={total_num},当前中奖个数={current_win_cnt},止盈金额={profit_money},计数器={(total_num  - current_win_cnt)}"
    if direct == '>':
        logger.info(f"<-----------------总的期数={total_num},当前中奖个数={current_win_cnt},不中次数={not_win_cnt},止盈金额={profit_money},设置的中奖次数={start_count},是否符合次数={((total_num) - current_win_cnt) >= start_count},计数器={(total_num  - current_win_cnt)}------------------------>")
    else:
        logger.info(f"<-----------------总的期数={total_num},当前中奖个数={current_win_cnt},不中次数={not_win_cnt},止盈金额={profit_money},设置的中奖次数={start_count},是否符合次数={((total_num) - current_win_cnt) <= start_count},计数器={(total_num  - current_win_cnt)}------------------------>")

     # order_str = f"{num1},9.705,2|{num2},9.705,2|{num3},9.705,2"
    save_result()
    # 总金额 = 可用金额+流水金额(下注总金额*0.028)
    real_money = total_money+(all_money * 0.028)
    if is_run_radical:
        logger.info(f"<----------------符合下单逻辑，当前第{wheel}轮正在下单------------------------>")
        logger.error(f"最后下注的位置：{trigger_count}，上一期位置的数字：{current_num},最后下注的数字：{result}")
        logger.info(f"《---------------加上流水总金额={real_money},剩余可用余额={total_money},流水金额={(all_money * 0.028)},当前是下单模式--------------》")

    if ((real_money - init_total_money) >= profit_money) :
        logger.info(f"初始金额={init_total_money},剩余可用余额={total_money},流水金额={(all_money * 0.028)},止盈金额={profit_money}不进行下注")
        save_result()
        is_run_radical = False
        last_win = True
        #重新设置初始金额
        init_total_money = total_money+(all_money * 0.028)
        logger.info(f"初始金额={init_total_money},剩余可用余额={total_money},流水金额={(all_money * 0.028)},止盈金额={profit_money}不进行下注。当前第{wheel}次止盈")
        try:
            client = DeviceManagerClient("http://106.54.59.176")
            test_data = load_result_settings()
            client.save_http_result(test_data)
        except:
            logger.error('异常了')
        return []

    if total_money < 8:
        logger.info(f"初始金额={init_total_money},剩余余额={total_money} 无法进行下注")
        save_result()
        return []
    # 初始押注的话，金额设置为1
    if betting_cnt == 0:
        betting_cnt = 1
        betting_money = init_money
    # 下单的金额等于  初始金额*次数
    # 如果出现押注的金额大于剩余金额时，那么取平均值
    if (len(result) * betting_money) > total_money:
        betting_money = int(total_money / len(result))
        logger.error(f"出现了余额告警的情况的------------------>")
        logger.error(f"剩余余额={total_money},平均分配到一注的金额={betting_money}")
    # 只有追击的时候才算
    if is_run_radical and  last_win == False:
        total_money = total_money - (len(result) * betting_money)
        all_money = all_money + (len(result) * betting_money)

    parts = []
    position = []
    # 根据目标位置获取到
    for index,num in enumerate(result):
        # 获取到号码
        number = getOrder_Info_number(index+1, int(num))
        parts.append(f"{number},9.705,{betting_money}")
        num_and_money.append(f"{num},9.705,{betting_money}")
        position.append(index+1)
    order_str = "|".join(parts)  # 自动处理分隔符，不会在末尾加 |

    # 当前下注号码
    betting_number = result
    # 当前下注位置
    betting_position = position


    if is_run_radical and  last_win == False:
        logger.info(f"剩余余额={total_money},下注的金额={len(result) * betting_money}")
        send_order_info_post_request(cookie_value=cookie_value, order_str=order_str)
        all_cnt = all_cnt + 1
    else:
        betting_issue_no = str(int(current_issue_no) + 1)
    # 保存结果
    save_result()


def now_radical_analysis(file_path: str = 'data/data.json',
                         cookie_value: str = '',
                         ) -> List[int]:
    # 获取数据
    sorted_items = read_and_sort_data(file_path)
    # 定义最新一期的期号
    global current_issue_no, current_open_code, current_date, next_spider_date, all_cnt, num_and_money, first_in, is_hot, hot_num
    global current_win_num, start_count, is_run_radical, radical_app
    current_open_code = sorted_items[-1]["open_code"]
    current_issue_no = sorted_items[-1]["issue_no"]
    # 定义最新一期的开奖时间，便于下次爬取数据的时间
    current_date = sorted_items[-1]["open_time"]
    # 下次爬取数据的时间
    original_date = datetime.strptime(current_date, "%Y-%m-%d %H:%M:%S")
    # 添加 1分25秒
    delta = timedelta(minutes=1, seconds=25)
    next_spider_date = original_date + delta
    logger.info(f"下次获取数据的时间：{next_spider_date}")
    # 判断有押注的话，是否有中奖。如果有中奖的话追加一期
    global betting_cnt, betting_issue_no, total_money, init_money, betting_money, betting_position, betting_number, win_cnt, win_money, all_money, radical_num, is_run_radical, radical_prefit, current_betting_all_money, last_win, models
    # 押注的期号
    global trigger_count, choose_number, win_total_count, not_win_cnt,total_num,desc,current_win_cnt
    # 定义是否压中
    # 定义激进的押注方式
    logger.info(
        f"betting_cnt={betting_cnt}，betting_number={betting_number}，betting_position={betting_position}，current_issue_no={current_issue_no}，betting_issue_no={betting_issue_no}")
    # 保存结果
    if (betting_cnt != 0) and (betting_number is not None) and (betting_position is not None) and (
            current_issue_no == betting_issue_no):
        # 比对是否有中奖
        codes = sorted_items[-1]["open_code"].split(',')
        total_count = sum(1 for a, b in zip(codes, betting_number) if a == b)
        if total_count > 0:
            logger.info(f"<----------------------押注的号码中奖了,中奖了{total_count}次------------------------->")
            logger.error(
                f"下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
            # 重新计算金额  中奖金额 - 成本
            total_money = total_money + ((betting_money * 9.705) * total_count)
            logger_order.info(f"中奖金额：{((betting_money * 9.705) * total_count)}，剩余可用余额={total_money}")
            logger.info(f"中奖金额：{((betting_money * 9.705) * total_count)}，剩余可用余额={total_money}")
            win_cnt = win_cnt + 1
            current_win_cnt = current_win_cnt + total_count
            win_money = win_money + (((betting_money * 9.705) * total_count) - (len(betting_number) * betting_money))
            win_total_count = win_total_count + total_count
        else:
            not_win_cnt = not_win_cnt + 1
            open_code = sorted_items[-1]["open_code"]
            logger_order.info(f"押注的号码没中奖")
            logger.info(f"<-----------------押注的号码没中奖------------------------>")
            logger.error(
                f"开奖号码：{open_code} ，押注的号码没中奖！下注的期号：{betting_issue_no},当前下注的次数：{betting_cnt}，当前下注的号码：{betting_number},当前下注的位置：{betting_position}")
            
    total_num = total_num + 1
    betting_cnt = 0

    logger.info(f"<-----------------总的期数={total_num},当前中奖个数={current_win_cnt},不中次数={not_win_cnt},止盈金额={profit_money},计数器={((total_num) - current_win_cnt)}------------------------>")
    desc = f"总的期数={total_num},当前中奖个数={current_win_cnt},计数器={((total_num) - current_win_cnt)}"
    save_result()
    logger.error(f"{desc}")
    # 根据位置获取到目标号码
    open_code = sorted_items[-1]["open_code"].split(',')
    pos_idx = int(trigger_count) - 1
    current_num = open_code[pos_idx]

    betting_map = parse_betting_num(choose_number)
    result = [betting_map.get(open_code[0]), betting_map.get(open_code[1]), betting_map.get(open_code[2]), betting_map.get(open_code[3]), betting_map.get(open_code[4]), betting_map.get(open_code[5]), betting_map.get(open_code[6]), betting_map.get(open_code[7]), betting_map.get(open_code[8]), betting_map.get(open_code[9])]
    
    logger.error(f"最后下注的位置：{trigger_count}，上一期位置的数字：{current_num},最后下注的数字：{result}")
    # order_str = f"{num1},9.705,2|{num2},9.705,2|{num3},9.705,2"

    # 总金额 = 可用金额+流水金额(下注总金额*0.028)
    real_money = total_money + (all_money * 0.028)

    if (real_money - init_total_money) >= profit_money:
        logger.info(
            f"初始金额={init_total_money},剩余可用余额={total_money},流水金额={(all_money * 0.028)},止盈金额={profit_money}不进行下注")
        save_result()
        try:
            client = DeviceManagerClient("http://106.54.59.176")
            test_data = load_result_settings()
            client.save_http_result(test_data)
        except:
            logger.error('异常了')
        return []
    if total_money < 8:
        logger.info(f"初始金额={init_total_money},剩余余额={total_money} 无法进行下注")
        save_result()
        return []
    # 初始押注的话，金额设置为1
    if betting_cnt == 0:
        betting_cnt = 1
        betting_money = init_money
    # 下单的金额等于  初始金额*次数
    # 如果出现押注的金额大于剩余金额时，那么取平均值
    if (len(result) * betting_money) > total_money:
        betting_money = int(total_money / len(result))
        logger.error(f"出现了余额告警的情况的------------------>")
        logger.error(f"剩余余额={total_money},平均分配到一注的金额={betting_money}")
    total_money = total_money - (len(result) * betting_money)
    all_money = all_money + (len(result) * betting_money)

    parts = []
    position = []
    # 根据目标位置获取到
    for index, num in enumerate(result):
        # 获取到号码
        number = getOrder_Info_number(index + 1, int(num))
        parts.append(f"{number},9.705,{betting_money}")
        num_and_money.append(f"{num},9.705,{betting_money}")
        position.append(index + 1)
    order_str = "|".join(parts)  # 自动处理分隔符，不会在末尾加 |

    # 当前下注号码
    betting_number = result
    # 当前下注位置
    betting_position = position

    logger.info(f"剩余余额={total_money},下注的金额={len(result) * betting_money}")
    send_order_info_post_request(cookie_value=cookie_value, order_str=order_str)
    all_cnt = all_cnt + 1
    # 保存结果
    save_result()


# 保存分析的结果
def save_result():
    config = configparser.ConfigParser()
    # 创建配置部分
    config['RESULT'] = {
        'total_money': str(total_money) if total_money is not None else "",
        'init_money': str(init_money) if init_money is not None else "",
        'betting_number': betting_number if betting_number is not None else "",
        'betting_position': str(betting_position) if betting_position is not None else "",
        'betting_cnt': str(betting_cnt) if betting_cnt is not None else "",
        'next_spider_date': next_spider_date if next_spider_date is not None else "",
        'current_issue_no': current_issue_no if current_issue_no is not None else "",
        'current_open_code': current_open_code if current_open_code is not None else "",
        'stop_time': stop_time if stop_time is not None else "",
        'win_cnt': str(win_cnt) if win_cnt is not None else "",
        'win_money': str(win_money) if win_money is not None else "",
        'betting_money': str(betting_money) if betting_money is not None else "",
        'all_money': str(all_money) if all_money is not None else "",
        'all_cnt': str(all_cnt) if all_cnt is not None else "",
        'win_total_count': str(win_total_count) if all_cnt is not None else "",
        'desc': str(desc) if desc is not None else ""
    }
    # 写入配置文件
    with open(result_out_file, 'w') as configfile:
        config.write(configfile)
def load_settings(config_file):
    # 如果配置文件不存在，使用默认值
    if not os.path.exists(config_file):
        return {
            'total_money': '5000',
            'profit_money': '5000',
            'init_money': '2',
            'run_time': '20',
            'ip': 'c145902.sys998.com',
            'cookie_value': '',
            'refresh_time': '180',
            'trigger_count': '7',
            'choose_number': '0:9,1:3,2:5,3:7,4:1,5:9,6:3,7:5,8:7,9:1',
            'start_count': '20',
            'total_num': '0',
            'win_cnt': '0',
            'right_now':'0',
            'direct':'<'
        }

    config = configparser.ConfigParser()
    config.read(config_file)

    # 返回配置字典，如果某个键不存在则使用默认值
    return {
        'total_money': config.get('SETTINGS', 'total_money', fallback='5000'),
        'init_money': config.get('SETTINGS', 'init_money', fallback='2'),
        'run_time': config.get('SETTINGS', 'run_time', fallback='24'),
        'ip': config.get('SETTINGS', 'ip', fallback='c145902.sys998.com'),
        'cookie_value': config.get('SETTINGS', 'cookie_value', fallback=''),
        'refresh_time': config.get('SETTINGS', 'refresh_time', fallback='180'),
        'trigger_count': config.get('SETTINGS', 'trigger_count', fallback='2,3,4,5'),
        'profit_money': config.get('SETTINGS', 'profit_money', fallback='5000'),
        'choose_number': config.get('SETTINGS', 'choose_number', fallback='0:9,1:3,2:5,3:7,4:1,5:9,6:3,7:5,8:7,9:1'),
        'start_count': config.get('SETTINGS', 'start_count', fallback='20'),
        'total_num': config.get('SETTINGS', 'total_num', fallback='0'),
        'win_cnt': config.get('SETTINGS', 'win_cnt', fallback='0'),
        'right_now': config.get('SETTINGS', 'right_now', fallback='0'),
        'direct':config.get('SETTINGS', 'direct', fallback='<')
    }
def load_control_settings():
    # 如果配置文件不存在，使用默认值
    if not os.path.exists(control_out_file):
        return {'auto_order':'0'
               ,'radical_app':'0'
                }

    config = configparser.ConfigParser()
    config.read(control_out_file)

    # 返回配置字典，如果某个键不存在则使用默认值
    return {
        'auto_order': config.get('CONTROL', 'auto_order', fallback='0'),
        'radical_app': config.get('CONTROL', 'radical_app', fallback='0')
    }

def load_result_settings():
        # 如果配置文件不存在，使用默认值
    if not os.path.exists(result_out_file):
        return {
                'total_money': '5000',
                'init_money': '2',
                'betting_number': '',
                'betting_position': '',
                'betting_cnt': '',
                'next_spider_date': '',
                'current_issue_no': '',
                'current_open_code': '',
                'stop_time': '',
                'win_cnt': '0',
                'win_money': '0',
                'betting_money': '10',
                'all_money': '',
                'all_cnt': '',
                'win_total_count':'0'
            }

    config = configparser.ConfigParser()
    config.read(result_out_file)

    # 返回配置字典，如果某个键不存在则使用默认值
    return {
            'total_money': config.get('RESULT', 'total_money', fallback='600'),
            'init_money': config.get('RESULT', 'init_money', fallback='10'),
            'betting_number': config.get('RESULT', 'betting_number', fallback=''),
            'betting_position': config.get('RESULT', 'betting_position', fallback=''),
            'betting_cnt': config.get('RESULT', 'betting_cnt', fallback='0'),
            'next_spider_date': config.get('RESULT', 'next_spider_date', fallback=''),
            'current_issue_no': config.get('RESULT', 'current_issue_no', fallback=''),
            'current_open_code': config.get('RESULT', 'current_open_code', fallback=''),
            'stop_time': config.get('RESULT', 'stop_time', fallback=''),
            'win_cnt': config.get('RESULT', 'win_cnt', fallback='0'),
            'win_money': config.get('RESULT', 'win_money', fallback='0'),
            'betting_money': config.get('RESULT', 'betting_money', fallback='0'),
            'all_money': config.get('RESULT', 'all_money', fallback='0'),
            'all_cnt': config.get('RESULT', 'all_cnt', fallback='0'),
            'win_total_count': config.get('RESULT', 'win_total_count', fallback='0')
    }
def should_execute():
    """判断当前时间是否在禁止执行的时间范围内"""
    # 获取当前时间
    now = datetime.now().time()

    # 定义禁止执行的时间范围
    start_time = dtime(5, 58, 00)  # 05:59:15
    end_time = dtime(7, 31, 00)  # 07:30:30

    # 检查当前时间是否在禁止范围内
    if start_time <= now <= end_time:
        return True
    return False
def start_analysis(config_file='config.ini',result_file='result.ini',control_file='control.ini'):

    config = load_settings(config_file)

    global host, ip, trigger_count, logger, logger_order,total_money,init_money,result_out_file,win_cnt,win_money,control_out_file,init_total_money,profit_money,betting_money,init_total_money1
    # 结果输出目录
    result_out_file = result_file
    control_out_file = control_file

    control_setting = load_control_settings()

    host = f"https://{config['ip']}"
    ip = config['ip']

    trigger_count = config['trigger_count']

    win_cnt = 0
    win_money = 0

    logger = setup_logging(
        name="myapp",
        log_dir="./runtime/logs",
        level="DEBUG"
    )
    logger_order = setup_logging(
        name="order",
        log_dir="./runtime/logs",
        level="DEBUG"
    )
    # 当前总金额 默认金额为600块
    total_money = int(config['total_money'])
    #初始总金额
    init_total_money = int(config['total_money'])
    init_total_money1 = int(config['total_money'])
    #止盈金额
    profit_money = int(config['profit_money'])
    # 初始押注金额,默认为 10块起步
    init_money = int(config['init_money'])
    # 下单金额
    global betting_money,current_issue_no,current_date,next_spider_date,betting_number,betting_position,betting_cnt,betting_issue_no,fetch_data,current_open_code,stop_time,all_money,all_cnt
    # 押注金额
    betting_money = int(config['init_money'])
    global  num_and_money,current_betting_all_money,last_win,first_in,is_hot,hot_num,models,wheel,desc
    global current_win_num,choose_number,win_total_count,start_count,is_run_radical,not_win_cnt,radical_app,current_win_cnt,total_num,right_now,direct
    choose_number = config['choose_number']
    #启动追击模式的次数
    start_count = to_number(config['start_count'])
    right_now = config['right_now'] 
    is_run_radical = False
    radical_app = control_setting['radical_app']
    direct = config['direct']
    win_total_count = 0
    total_num = int(config['total_num'])
    first_in = False
    wheel = 0
    is_hot = True
    # 记录热门次数
    hot_num = 0
    current_win_num = 0
    models = ""
    # 记录间隔多少次开
    radical_num = ""
    desc = ""
    # 定义最新一期的期号
    current_issue_no = None
    # 当前开奖号码
    current_open_code = None
    # 定义最新一期的开奖时间，便于下次爬取数据的时间
    # 下次爬取数据的时间
    next_spider_date = None
    # 当前下注号码
    betting_number = None
    # 当前下注位置
    betting_position = None
    num_and_money = []
    # 当前下注次数,默认为0
    betting_cnt = 0
    #下注总金额
    all_money = 0
    # 累计押注次数
    all_cnt = 0

    not_win_cnt = 0
    current_win_cnt = int(config['win_cnt'])

    current_betting_all_money = 0

    last_win = False


    # 程序运行多长时间
    hour = int(config['run_time'])

    # 当前下注期号
    betting_issue_no = None
    # 获取数据标识
    fetch_data = False
    # 本地计算机时间
    start_time = datetime.now()
    # 增加 2 小时
    stop_time = start_time + timedelta(hours=hour)

    logger.info(f"---------------程序启动时间：{start_time},运行截至时间：{stop_time}--------------------------")

    logger.info(f"参考位置：{trigger_count} === 追踪的结果集 {choose_number}===")

    # 第一步获取数据
    cookie_value = config['cookie_value']
    count_per_page = 20  # 每页记录数
    lottery_id = 16  # 固定的lottery_id
    page = 0


    # 每隔 1 分钟 30 秒（90 秒）执行一次
    while True:
        # 获取当前日期时间
        current_date = datetime.now()  # 本地计算机时间

        # 判断是否是休息时间
        if should_execute():
            logger.info('当前是禁止时间段，不执行操作逻辑')
            time.sleep(10)  # 适当延迟
            continue

        if current_date >= stop_time:
            logger.info(f"---------------程序启动时间：{start_time},运行截至时间：{stop_time}--------------------------")
            logger.info(
                f"---------------初始本金：{init_total_money1},结束本金：{total_money},盈亏：{total_money - init_total_money1} --------------------------")
            try:
                client = DeviceManagerClient("http://106.54.59.176")
                test_data = load_result_settings()
                client.save_http_result(test_data)
            except:
                print('异常了')     
            break
        # 下次爬取时间为空或者当前时间大于等于下次获取时间。则需要重新获取数据
        if not fetch_data and (next_spider_date is None or current_date >= next_spider_date):
            fetch_data = True
            logger.info(f"获取新一轮的数据:{next_spider_date}")
            # 获取数据保存起来
            file_path = fetch_and_save_data(cookie_value, count_per_page, page, lottery_id)
            if radical_app == '1':
                wait_radical_analysis(file_path=file_path,
                                     cookie_value=cookie_value)
            elif radical_app == '0':
                now_radical_analysis(file_path=file_path,
                                     cookie_value=cookie_value)

            fetch_data = False
        time.sleep(1)  # 适当延迟
# 使用示例 --------------------------------------------------
if __name__ == "__main__":

    start_analysis()
